﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Specification
{
    public abstract class CompositeSpecification<T> : ISpecification<T>
    {
        protected IEnumerable<ISpecification<T>> _Specifications;
        public abstract bool isSatisfiedBy(T objekt);

        public List<ISpecification<T>> Specifications
        {
            get
            {
                return new List<ISpecification<T>>(this._Specifications);
            }
        }
        public IEnumerable<string> Messages
        {
            get
            {
                List<string> SpecificationMessages = new List<string>();
                foreach (ISpecification<T> specification in this._Specifications)
                {
                    if (specification is LeafSpecification<T>)
                        SpecificationMessages.Add(((LeafSpecification<T>)specification).Message);
                    if (specification is CompositeSpecification<T>)
                        SpecificationMessages.AddRange(((CompositeSpecification<T>)specification).Messages);
                }
                return SpecificationMessages;
            }
        }
        public ISpecification<T> remainderUnsatisfiedBy(T Candidate)
        {
            if (isSatisfiedBy(Candidate))
                return null;
            else
                return remainderUnsatisfiedAsCompositeSpecification(Candidate);
        }

        private ISpecification<T> remainderUnsatisfiedAsCompositeSpecification(T Candidate)
        {
            CompositeSpecification<T> instance = Activator.CreateInstance(this.GetType()) as CompositeSpecification<T>;
            instance._Specifications = remaindersUnsatisfiedBy(Candidate);
            return instance;
        }
        private IEnumerable<ISpecification<T>> remaindersUnsatisfiedBy(T Candidate)
        {
            foreach (ISpecification<T> spec in this._Specifications)
                yield return spec.remainderUnsatisfiedBy(Candidate);
        }
    }
}
